/*
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
package com.l2emu.gameserver.model;

import javolution.util.FastList;

import com.l2emu.Config;
import com.l2emu.util.Rnd;

/**
*
* @author  Fulminus
*/
public class L2DropCategory
{
	private FastList<L2DropData> _drops;
	private int _categoryChance; // a sum of chances for calculating if an item will be dropped from this category
	private int _categoryBalancedChance; // sum for balancing drop selection inside categories in high rate servers
	private int _categoryType;

	public L2DropCategory(int categoryType)
	{
		_categoryType = categoryType;
		_drops = new FastList<L2DropData>(0);
		_categoryChance = 0;
		_categoryBalancedChance = 0;
	}

	public void addDropData(L2DropData drop, boolean raid)
	{
       boolean found = false;
       
	    if (drop.isQuestDrop()) {
	    //if (_questDrops == null)
	    //	_questDrops = new FastList<L2DropData>(0);
	    //_questDrops.add(drop);
	    } 
	    else 
	    {
           if (Config.CUSTOM_DROPLIST_TABLE)
           {
               // If the drop exists is replaced
               for (L2DropData d : _drops)
               {
                   if (d.getItemId() == drop.getItemId())
                   {
                       d.setMinDrop(drop.getMinDrop());
                       d.setMaxDrop(drop.getMaxDrop());
                       if (d.getChance() != drop.getChance())
                       {
                           // Re-calculate Chance
                           _categoryChance -= d.getChance();
                           _categoryBalancedChance -= Math.min((d.getChance() * Config.RATE_DROP_ITEMS), L2DropData.MAX_CHANCE);
                           d.setChance(drop.getChance());
                           _categoryChance += d.getChance();
                           _categoryBalancedChance += Math.min((d.getChance() * Config.RATE_DROP_ITEMS), L2DropData.MAX_CHANCE);
                       }
                       found = true;
                       break;
                   }
               }
           }
	        
           if (!found)
           {
               _drops.add(drop);
               _categoryChance += drop.getChance();
               // for drop selection inside a category: max 100 % chance for getting an item, scaling all values to that.
               _categoryBalancedChance += Math.min((drop.getChance()*(raid?Config.RATE_DROP_ITEMS_BY_RAID : Config.RATE_DROP_ITEMS)),L2DropData.MAX_CHANCE);
           }
	    }
	}

   public FastList<L2DropData> getAllDrops()
   {
   	return _drops;
   }

   public void clearAllDrops()
   {
   	_drops.clear();
   }

   public boolean isSweep()
   {
   	return (getCategoryType()==-1);
   }

   // this returns the chance for the category to be visited in order to check if
   // drops might come from it.  Category -1 (spoil) must always be visited
   // (but may return 0 or many drops)
   public int getCategoryChance()
   {
   	if (getCategoryType() >= 0)
   		return _categoryChance;
   	else
   		return L2DropData.MAX_CHANCE;
   }

   public int getCategoryBalancedChance()
   {
   	if (getCategoryType() >= 0)
   		return _categoryBalancedChance;
   	else
   		return L2DropData.MAX_CHANCE;
   }

   public int getCategoryType()
   {
   	return _categoryType;
   }

   /**
    * useful for seeded conditions...the category will attempt to drop only among
    * items that are allowed to be dropped when a mob is seeded.
    * Previously, this only included adena.  According to sh1ny, sealstones are also
    * acceptable drops.
    * if no acceptable drops are in the category, nothing will be dropped.
    * otherwise, it will check for the item's chance to drop and either drop
    * it or drop nothing.
    *
    * @return acceptable drop when mob is seeded, if it exists.  Null otherwise.
    */
   public synchronized L2DropData dropSeedAllowedDropsOnly()
   {
   	FastList<L2DropData> drops = new FastList<L2DropData>();
   	int subCatChance = 0;
   	for (L2DropData drop : getAllDrops())
       {
   		if ((drop.getItemId() == 57) || (drop.getItemId() == 6360)|| (drop.getItemId() == 6361)|| (drop.getItemId() == 6362))
   		{
           	drops.add(drop);
       		subCatChance += drop.getChance();
   		}
       }

   	// among the results choose one.
       int randomIndex = Rnd.get(subCatChance);
       int sum = 0;
       for (L2DropData drop : drops)
       {
       	sum += drop.getChance();

       	if (sum > randomIndex)       // drop this item and exit the function
       	{
       		drops.clear();
       		drops=null;
       		return drop;
       	}
       }
         // since it is still within category, only drop one of the acceptable drops from the results.
   	return null;
   }

/**
* ONE of the drops in this category is to be dropped now.
* to see which one will be dropped, weight all items' chances such that
* their sum of chances equals MAX_CHANCE.
* since the individual drops have their base chance, we also ought to use the
* base category chance for the weight.  So weight = MAX_CHANCE/basecategoryDropChance.
* Then get a single random number within this range.  The first item
* (in order of the list) whose contribution to the sum makes the
* sum greater than the random number, will be dropped.
*
* Edited: How _categoryBalancedChance works in high rate servers:
* Let's say item1 has a drop chance (when considered alone, without category) of
* 1 % * RATE_DROP_ITEMS and item2 has 20 % * RATE_DROP_ITEMS, and the server's
* RATE_DROP_ITEMS is for example 50x. Without this balancer, the relative chance inside
* the category to select item1 to be dropped would be 1/26 and item2 25/26, no matter
* what rates are used. In high rate servers people usually consider the 1 % individual
* drop chance should become higher than this relative chance (1/26) inside the category,
* since having the both items for example in their own categories would result in having
* a drop chance for item1 50 % and item2 1000 %. _categoryBalancedChance limits the
* individual chances to 100 % max, making the chance for item1 to be selected from this
* category 50/(50+100) = 1/3 and item2 100/150 = 2/3.
* This change doesn't affect calculation when drop_chance * RATE_DROP_ITEMS < 100 %,
* meaning there are no big changes for low rate servers and no changes at all for 1x
* servers.
*
* @return selected drop from category, or null if nothing is dropped.
*/
   public synchronized L2DropData dropOne(boolean raid)
   {
       int randomIndex = Rnd.get(getCategoryBalancedChance());
       int sum = 0;
       for (L2DropData drop : getAllDrops())
       {
       	sum += Math.min((drop.getChance()*(raid?Config.RATE_DROP_ITEMS_BY_RAID : Config.RATE_DROP_ITEMS)),L2DropData.MAX_CHANCE);

       	if (sum >= randomIndex)       // drop this item and exit the function
       		return drop;
       }
       return null;
   }
}
